﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.IO;
using System.Xml.Serialization;
using GuestList.Models;
using System.Collections.ObjectModel;
using System.Windows.Input;
using GuestList.Commands;
using System.Drawing.Printing;
using System.Windows.Controls;

namespace GuestList.ViewModels
{
    public class GuestListVM : WindowVM
    {
        static XmlSerializer serializer = new XmlSerializer(typeof(GuestList.Models.GuestList));

        public GuestList.Models.GuestList Guests { get; set; }


        private ObservableCollection<InvitationVM> _invitations = new ObservableCollection<InvitationVM>();
        public ObservableCollection<InvitationVM> Invitations
        {
            get { return _invitations; }
            set
            {
                _invitations = value;
                Notify("Invitations");
            }
        }

        private InvitationVM _selectedInvitation = null;
        public InvitationVM SelectedInvitation
        {
            get { return _selectedInvitation; }
            set
            {
                _selectedInvitation = value;
                Notify("SelectedInvitation");
            }
        }

        public int InvitationTotal
        {
            get { return Guests.Invitations.Count; }
        }

        public int CeremonyInserts
        {
            get { return Guests.Invitations.Where(x => x.InvitationType == InvitationType.Ceremony).Count(); }
        }

        public int CeremonyTotal
        {
            get
            {
                int total = 0;
                foreach (var item in Guests.Invitations)
                {
                    if (item.InvitationType == InvitationType.Ceremony)
                    {
                        total++;
                        total += item.OtherGuests.Count;
                    }
                }
                return total;
            }
        }

        public int ReceptionTotal
        {
            get
            {
                int total = 0;
                foreach (var item in Guests.Invitations)
                {
                    total++;
                    total += item.OtherGuests.Count;
                }
                return total;
            }
        }

        public decimal WeightedCeremonyTotal
        {
            get
            {
                decimal total = 0;
                foreach (var item in Guests.Invitations)
                {
                    if (item.InvitationType == InvitationType.Ceremony)
                    {
                        total += item.Weight;
                        total += item.OtherGuests.Count * item.Weight;
                    }
                }
                return total;
            }
        }

        public decimal WeightedReceptionTotal
        {
            get
            {
                decimal total = 0;
                foreach (var item in Guests.Invitations)
                {
                    total += item.Weight;
                    total += item.OtherGuests.Count * item.Weight;
                }
                return total;
            }
        }

        public int UnsentThankYouNoteCount
        {
            get
            {
                return Guests.Invitations.Where(x => !x.HaveSentThankYou && !string.IsNullOrWhiteSpace(x.GiftDescription)).Count();
            }
        }

        public ObservableCollection<object> RelationGrouping
        {
            get
            {
                return new ObservableCollection<object>(
                    from i in Invitations.Select(x => x.Model)
                    group i by i.Relation into g
                    select new
                    {
                        Relation = g.Key,
                        InvitationCount = g.Count(),
                        PersonCount = g.Sum(x => x.OtherGuests.Count + 1),
                        WeightedReception = g.Sum(x => (x.OtherGuests.Count + 1) * x.Weight)
                    });


            }
        }

        public GuestListVM(Window window)
            : base(window)
        {
            window.Closing += new System.ComponentModel.CancelEventHandler(window_Closing);
            LoadGuests();
        }

        private void LoadGuests()
        {
            OpenFile(UserSettings.Default.SaveLocation);
        }

        private void OpenFile(string path)
        {
            if (File.Exists(path))
            {
                using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
                {
                    Guests = (Models.GuestList)serializer.Deserialize(fs);
                }
            }
            else
            {
                Guests = new Models.GuestList();
            }
            Invitations.Clear();
            foreach (var invitation in Guests.Invitations)
            {
                Invitations.Add(new InvitationVM(invitation));
            }
        }

        void window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            SaveFile(UserSettings.Default.SaveLocation);
        }

        private void SaveFile(string path)
        {
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            {
                fs.SetLength(0);
                Guests.Invitations = new ObservableCollection<Invitation>(Guests.Invitations
                    .OrderBy(x => x.PrimaryGuest.LastName)
                    .ThenBy(x => x.PrimaryGuest.FirstName)
                    .ToList());
                serializer.Serialize(fs, Guests);
            }
        }

        #region Commands

        public RelayCmd OpenSelectedInvitationCmd { get { return new RelayCmd(OpenSelectedInvitation, () => SelectedInvitation != null); } }

        private void OpenSelectedInvitation()
        {
            SelectedInvitation.Show();
        }

        public RelayCmd AddGuestCmd
        {
            get
            {
                return new RelayCmd
                (
                    CreateInvitation,
                    () => true
                );
            }
        }

        private void CreateInvitation()
        {
            var invitation = new Models.Invitation { PrimaryGuest = new Models.Person() };
            var vm = new InvitationVM(invitation);
            Invitations.Add(vm);
            Guests.Invitations.Add(invitation);
            vm.Show();
        }

        public RelayCmd RemoveSelectedInvitationCmd
        {
            get
            {
                return new RelayCmd
                (
                    () => 
                    {
                        if (Guests.Invitations.Contains(SelectedInvitation.Model))
                        {
                            Guests.Invitations.Remove(SelectedInvitation.Model);
                        }
                        Invitations.Remove(SelectedInvitation);
                    },
                    () => SelectedInvitation != null
                );
            }
        }

        public GestureCmd SaveCmd 
        {
            get { return new GestureCmd(Save, () => true, Window, new KeyGesture(Key.S, ModifierKeys.Control)); }
        }

        private void Save()
        {
            SaveFile(UserSettings.Default.SaveLocation);
        }

        public RelayCmd SaveAsCmd
        {
            get { return new RelayCmd(SaveAs, () => true); }
        }

        private void SaveAs()
        {
            var dialog = new Microsoft.Win32.SaveFileDialog();
            dialog.FileOk += delegate
            {
                SaveFile(dialog.FileName);
            };
            dialog.ShowDialog();
        }

        public RelayCmd OpenCmd
        {
            get { return new RelayCmd(Open, ()=> true); }
        }

        private void Open()
        {
            if (MessageBox.Show("Would you like to save your current file?", "Save File", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                SaveAs();
            }
            var dialog = new Microsoft.Win32.OpenFileDialog();
            dialog.FileOk += delegate
            {
                OpenFile(dialog.FileName);
            };
            dialog.ShowDialog();
        }

        public RelayCmd StatsRefreshCmd
        {
            get
            {
                return new RelayCmd
                (
                    () =>
                    {
                        Notify("CeremonyTotal");
                        Notify("ReceptionTotal");
                        Notify("InvitationTotal");
                        Notify("WeightedCeremonyTotal");
                        Notify("WeightedReceptionTotal");
                        Notify("RelationGrouping");
                        Notify("CeremonyInserts");
                        Notify("UnsentThankYouNoteCount");
                    },
                    ()=>true
                );
            }
        }

        public RelayCmd ShowOptionsCmd
        {
            get { return new RelayCmd(ShowOptions, () => true); }
        }

        private void ShowOptions()
        {
            OptionsWindow options = new OptionsWindow();
            OptionsVM vm = new OptionsVM();
            vm.Close += delegate { options.Close(); };
            options.DataContext = vm;
            options.Show();
        }

        #endregion
    }
}
